package org.dtrd.modules.record.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.RecordType;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.record.entity.bean.*;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninWaistline;
import org.dtrd.modules.record.mapper.DtrdEntRdWaistlineMapper;
import org.dtrd.modules.record.service.IWaistlineRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 萧
 * @date:2021-08-22
 **/
@Service
@DS("multi-datasource1")
@Slf4j
public class WaistlineRecordServiceImpl extends ServiceImpl<DtrdEntRdWaistlineMapper, DtrdEntRdSigninWaistline> implements IWaistlineRecordService {

    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;

    @Override
    public DtrdEntRdSigninWaistline transformRecord(CheckinRecord record) {
        DtrdEntRdSigninWaistline dt = new DtrdEntRdSigninWaistline().init();
        dt.setWaistlineRemark(record.getRemark());
        dt.setWaistlineValue(record.getWaist());
        dt.setPatientId(record.getPatientId());
        dt.setRecordTime(parseStringAsDateTime(record.getRecordTime()));
        dt.setRecordDate(parseStringAsDate(record.getRecordTime()));
        dt.setRecordPhoto(record.getImages());
        return dt;
    }

    @Override
    public CheckinRecord transformPO(DtrdEntRdSigninWaistline po) {
        if (po == null) {
            return null;
        }
        CheckinRecord record = new CheckinRecord();
        record.setRecordTime(DateUtils.formatTime(po.getRecordTime()));
        record.setRecordTimeHm(DateUtils.formatShortTime(po.getRecordTime()));
        record.setDataId(po.getDataId());
        record.setImages(po.getRecordPhoto());
        record.setPatientId(po.getPatientId());
        record.setRecordType(Constant.RecordType.WAIST.getType());
        record.setRecordTypeName(Constant.RecordType.WAIST.getName());
        record.setRemark(po.getWaistlineRemark());
        record.setWaist(po.getWaistlineValue());
        return record;
    }

    @Override
    public LambdaQueryWrapper<DtrdEntRdSigninWaistline> generateSelectRecordByDateQuery(Integer patientId, String date, Integer subType) {
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> query = new LambdaQueryWrapper<>();
        query.eq(DtrdEntRdSigninWaistline::getIsDel, 0).eq(DtrdEntRdSigninWaistline::getPatientId, patientId).eq(DtrdEntRdSigninWaistline::getRecordDate, date);
        return query;
    }

    @Override
    public boolean saveWaistLineRecord(WaistLineBean waistLineBean) {
        DtrdEntRdSigninWaistline po = new DtrdEntRdSigninWaistline();
        if (waistLineBean.getId() == null) {
            po = po.init();
        }
        po.parseFromDTO(waistLineBean);
        LambdaUpdateWrapper<DtrdEntRdSigninWaistline> wrapper = Wrappers.lambdaUpdate(DtrdEntRdSigninWaistline.class)
                .eq(DtrdEntRdSigninWaistline::getRecordDate, po.getRecordDate())
                .eq(DtrdEntRdSigninWaistline::getPatientId, waistLineBean.getPatientId());
        boolean result = saveOrUpdate(po, wrapper);
        log.info("WaistlineRecordServiceImpl.saveWaistLineRecord.[waistLineBean] after save patientId=" + po.getPatientId() + "; result=" + result + "; dataId=" + po.getDataId());
        if (po.getDataId() == null) {
            po = getOne(wrapper);
        }
        // 补充打卡
        signinRecordService.saveSigninRecord(po.getDataId(), 0, mapper ->
                mapper.apply(waistLineBean.getPatientId())
                        .withRecordType(RecordType.WAIST.getType())
                        .withRecordTime(waistLineBean.getRecordTime())
                        .withRecordValue(waistLineBean.getWaistLineValue() + "")
                        .withRemark(waistLineBean.getWaistLineRemark())
                        .withImages(waistLineBean.getRecordPhoto())
                        .build()
        );
//        Date recordDate = waistline.getRecordDate();
//        DtrdEntRdSigninWaistline po = getOne(wrapper);
//        signinRecordService.saveSigninRecord(po.getDataId(), waistline.getPatientId(),
//                Constant.RecordType.WAIST.getType(), 0,
//                DateUtils.formatDate(recordDate, DateUtils.date_sdf.get().toPattern()));
        return result;
    }

    @Override
    public WaistLineChart getWaistLineChart(int patientId, String startDate, String endDate) {
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .ge(DtrdEntRdSigninWaistline::getRecordDate, startDate)
                .le(DtrdEntRdSigninWaistline::getRecordDate, endDate)
                .orderByAsc(DtrdEntRdSigninWaistline::getRecordDate);
        List<DtrdEntRdSigninWaistline> waistRecords = list(queryWrapper);
        WaistLineChart waistLineChart = new WaistLineChart();
        ArrayList<String> recordTimes = new ArrayList<>(waistRecords.size());
        ArrayList<Integer> waistLineValues = new ArrayList<>(waistRecords.size());
        waistRecords.forEach(waist -> {
            recordTimes.add(DateUtils.formatDate(waist.getRecordDate()));
            waistLineValues.add(waist.getWaistlineValue());
        });
        // 设置返回数据
        waistLineChart.setDates(recordTimes);
        // 应前端要求，返回格式为二重数组 萧 2021-11-23 15:17:53
        List<List<Integer>> list = new ArrayList<>(1);
        list.add(waistLineValues);
        waistLineChart.setValue(list);
        return waistLineChart;
    }

    @Override
    public List<DtrdEntRdSigninWaistline> getPeriodWaistLine(Integer patientId, String startDate, String endDate) {
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> queryWrapper = baseQueryWrapper()
                .isNotNull(DtrdEntRdSigninWaistline::getWaistlineValue)
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .ge(startDate !=null, DtrdEntRdSigninWaistline::getRecordDate, startDate)
                .le(endDate!=null, DtrdEntRdSigninWaistline::getRecordDate, endDate);
        return list(queryWrapper);
    }

    @Override
    public Integer getFoodWaistLineDateCount(Integer patientId, String startDate, String endDate) {
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .ge(DtrdEntRdSigninWaistline::getRecordDate, startDate)
                .le(DtrdEntRdSigninWaistline::getRecordDate, endDate)
                // 还是得分组
                .groupBy(DtrdEntRdSigninWaistline::getRecordDate)
                .select(DtrdEntRdSigninWaistline::getRecordDate);
        return list(queryWrapper).size();
    }

    @Override
    public List<WaistDailyRecord> getWaistLineRecordByRange(Integer patientId, String startDate, String endDate, Integer page, Integer pageSize) {
        // 查询指定范围内的所有记录
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .ge(DtrdEntRdSigninWaistline::getRecordDate, startDate)
                .le(DtrdEntRdSigninWaistline::getRecordDate, endDate)
                .orderByDesc(DtrdEntRdSigninWaistline::getRecordTime);
        List<DtrdEntRdSigninWaistline> waistlineRecords = list(queryWrapper);
        // 根据日期分组
        Map<Date, List<DtrdEntRdSigninWaistline>> dateToWaistRecord = waistlineRecords.stream()
                .collect(Collectors.groupingBy(DtrdEntRdSigninWaistline::getRecordDate));
        // 创建每日列表
        ArrayList<WaistDailyRecord> dailyWaistRecords = new ArrayList<>(pageSize);
        if (MapUtil.isNotEmpty(dateToWaistRecord)) {
            Set<Date> dateSet = dateToWaistRecord.keySet();
            dateSet.forEach(recordDate -> {
                WaistDailyRecord waistDailyRecord = new WaistDailyRecord();
                waistDailyRecord.setRecordDate(DateUtils.formatDate(recordDate, DateUtils.date_sdf.get().toPattern()));
                // 每个分组中只取createTime最大的那个
                List<DtrdEntRdSigninWaistline> dateWaistRecord = dateToWaistRecord.get(recordDate);
                Optional<DtrdEntRdSigninWaistline> waistline = dateWaistRecord.stream()
                        .max(Comparator.comparing(DtrdEntRdSigninWaistline::getCreateTime));
                waistline.ifPresent(po -> {
                    waistDailyRecord.setWaistLineRecordBean(new WaistLineBean().parseFromPo(po));
                    waistDailyRecord.setWaistLineValue(po.getWaistlineValue());
                });
                dailyWaistRecords.add(waistDailyRecord);
            });
        }
        dailyWaistRecords.sort(Comparator.comparing(WaistDailyRecord::getRecordDate, Comparator.reverseOrder()));
        // 处理分页
        int pageState = (page - 1) * pageSize;
        return dailyWaistRecords.stream().skip(pageState).limit(pageSize).collect(Collectors.toList());
    }

    @Override
    public WaistLineStatistics getWaistLineStatistics(int patientId, String startDate, String endDate) {
        // 查询指定范围内的所有记录
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .ge(DtrdEntRdSigninWaistline::getRecordDate, startDate)
                .le(DtrdEntRdSigninWaistline::getRecordDate, endDate)
                .orderByDesc(DtrdEntRdSigninWaistline::getRecordTime);
        List<DtrdEntRdSigninWaistline> waistlineRecords = list(queryWrapper);
        IntSummaryStatistics statistics = waistlineRecords.stream()
                .mapToInt(DtrdEntRdSigninWaistline::getWaistlineValue)
                .summaryStatistics();
        // 设置返回数据
        WaistLineStatistics waistLineStatistics = new WaistLineStatistics();
        waistLineStatistics.setWaistLineMax(statistics.getMax());
        waistLineStatistics.setWaistLineMin(statistics.getMin());
        waistLineStatistics.setWaistLineAvg(statistics.getAverage());
        return waistLineStatistics;
    }

    @Override
    public AvgRecordBean getAvgValue(Integer patientId, String startDate, String endDate) {
        return baseMapper.getAvgValue(patientId, startDate, endDate);
    }

    @Override
    public Integer getAvgWaist(Integer patientId, String startOfWeek, String endOfWeek) {
        return baseMapper.getAvgWaist(patientId, startOfWeek, endOfWeek);
    }

    @Override
    public DtrdEntRdSigninWaistline getWaistLineRecordLatestByPatientId(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> wrapper = Wrappers.lambdaQuery(DtrdEntRdSigninWaistline.class)
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .orderByDesc(DtrdEntRdSigninWaistline::getCreateTime)
                .last("limit 1");
        return getOne(wrapper);
    }

    @Override
    public Float getFirstWaistlineValue(Integer patientId) {
        // signinWaistline 表里
        LambdaQueryWrapper<DtrdEntRdSigninWaistline> waistlineQueryWrapper = Wrappers.lambdaQuery(DtrdEntRdSigninWaistline.class)
                .eq(DtrdEntRdSigninWaistline::getPatientId, patientId)
                .eq(DtrdEntRdSigninWaistline::getIsDel, 0)
                .isNotNull(DtrdEntRdSigninWaistline::getWaistlineValue)
                .orderByAsc(DtrdEntRdSigninWaistline::getRecordTime)
                .last("limit 1");
        DtrdEntRdSigninWaistline queryWaist = this.getOne(waistlineQueryWrapper);
        // 有记录就返回对应记录的
        return queryWaist != null? new Float(queryWaist.getWaistlineValue()):null;
    }

    private LambdaQueryWrapper<DtrdEntRdSigninWaistline> baseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntRdSigninWaistline.class).eq(DtrdEntRdSigninWaistline::getIsDel, 0);
    }
}
